<?php

namespace App\Exports;

use App\Models\AfterSaleOrder;
use App\Models\Order;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

class OrderExport extends BaseExport implements WithCustomValueBinder, FromQuery
{
    public function __construct(\Illuminate\Http\Request $request = null)
    {
        parent::__construct($request);

        activity()
            ->by(\Auth::user())
            ->withProperty('ip', app('request')->ip())
            ->log(sprintf('导出订单'));
    }

    public function headings(): array
    {
        return [
            '订单编号',
            '商品名称',
            '商品规格',
            '活动编号',
            '商品总数',
            '代理名称',
            '代理手机号',
            '收件人姓名',
            '收件人手机号',
            '地址',
            '订单总额',
            '商品总额',
            '零售价',
            '状态',
            '管理备注',
            '创建时间',
        ];
    }

    public function map($row): array
    {
        $row = $row->toArray();

        // 售后 退货 退款 的剔除
        $afterSaleSkus = [];
        foreach ($row['after_sale_order'] as $afterSaleItem) {
            foreach ($afterSaleItem['after_sale_order_skus'] as $afterSaleItemSkus) {
                $skuId = $afterSaleItemSkus['sku_snapshot']['id'];
                !isset($afterSaleSkus[$skuId]) && $afterSaleSkus[$skuId] = 0;
                $afterSaleSkus[$skuId] += $afterSaleItemSkus['amount'];
            }
        }

        // 订单 SKU
        $skuList = [];
        $amount = 0;
        $retailPrice = 0;
        foreach ($row['skus'] as $sku) {
            $remaining = $sku['amount'];
            $skuId = $sku['sku_snapshot']['id'];
            if (isset($afterSaleSkus[$skuId])) {
                $remaining -= $afterSaleSkus[$skuId];
//                if ($remaining === 0) {
//                    continue; // 退货 退款 售后完了
//                }
            }

            $skuList[] = implode(' | ', array_map(fn($value) => $value['content'], $sku['sku_snapshot']['values'])) . ' * ' . $remaining;
            $amount += $remaining;
            $retailPrice += $remaining * $sku['sku_snapshot']['external_guide_price'];
        }

        return [
            $row['numbering'], // 订单编号
            $row['commodity_snapshot']['name'], // 商品名称
            implode('; ', $skuList), // 商品规格
            $row['commodity_activity_snapshot']['numbering'] ?? '', // 活动编号
            $amount, // 商品总数
            $this->removeUncommonWords($this->removeEmoji($row['agent']['name'])), // 代理名称
            $row['agent']['phone'], // 代理手机号
            $this->removeUncommonWords($this->removeEmoji($row['client_name'])), // 收件人姓名
            $row['client_phone'], // 收件人手机号
            $this->removeUncommonWords($this->removeEmoji($row['client_address'])), // 地址
            number_format($row['total_amount'] / 100, 2), // 订单总额
            number_format(($row['total_amount'] - $row['freight']) / 100, 2), // 商品总额 = 订单总额 - 运费总额
            number_format($retailPrice / 100, 2), // 零售价
            Order::STATUS_MAP[$row['status']], // 状态
            $row['management_notes'], // 管理备注
            $row['created_at'], // 创建时间
        ];
    }

    /**
     * @return \Illuminate\Database\Query\Builder
     */
    public function query()
    {
        return Order::query()
            ->withoutGlobalScope('orderByIdDesc')
            ->with(['agent', 'skus', 'afterSaleOrder' => function ($query) {
                $query
                    ->with('afterSaleOrderSkus')
                    ->whereIn('type', [
                        AfterSaleOrder::TYPE_RETURN,
                        AfterSaleOrder::TYPE_REFUND_ONLY
                    ])
                    ->where('status', AfterSaleOrder::STATUS_PASSED);
            }])
            ->when($this->request['numbering'] ?? '', function (Builder $builder, $numbering) {
                $builder->where('orders.numbering', $numbering);
            })
            ->when($this->request['commodity_numbering'] ?? '', function (Builder $builder, $commodityNumbering) {
                $builder->where('orders.commodity_numbering', $commodityNumbering);
            })
            ->when($this->request['commodity_activity_id'] ?? 0, function (Builder $builder, $commodityActivityId) {
                $builder->where('orders.commodity_activity_id', $commodityActivityId);
            })
            ->when($this->request['status'] ?? 0, function (Builder $builder, $status) {
                $builder->where('orders.status', $status);
            })
            ->when($this->request['client_search_name'] ?? '', function (Builder $builder, $clientSearch) {
                $builder->where('orders.client_name', 'like', "$clientSearch%");
            })
            ->when($this->request['client_search_phone'] ?? '', function (Builder $builder, $clientSearch) {
                $builder->where('orders.client_phone', 'like', "$clientSearch%");
            })
            ->when($this->request['agent_search'] ?? '', function (Builder $builder, $agentSearch) {
                $builder
                    ->join('agents', 'agents.id', '=', 'orders.agent_id')
                    ->where(function (Builder $builder) use ($agentSearch) {
                        $builder->when(
                            is_numeric($agentSearch) && mb_strlen($agentSearch) === 11,
                            function (Builder $builder) use ($agentSearch) {
                                $builder->where('agents.phone', $agentSearch);
                            },
                            function (Builder $builder) use ($agentSearch) {
                                $builder->where('agents.name', 'like', "$agentSearch%");
                            });
                    });
            })
            ->when($this->request['created_at_begin'] ?? '', function (Builder $query, $createdAtBegin) {
                $query->where('orders.order_date', '>=', $createdAtBegin);
            })
            ->when($this->request['created_at_end'] ?? '', function (Builder $query, $createdAtEnd) {
                $query->where('orders.order_date', '<=', $createdAtEnd);
            })
            ->when(empty(Arr::except($this->request, ['s', 'page', 'per_page'])), function (Builder $query) {
                $query->orderByDesc('orders.order_date');
            }, function (Builder $query) {
                $query->orderByDesc('orders.id');
            })
            ->select([
                'orders.id',
                'orders.agent_id',
                'orders.numbering',
                'orders.numbering',
                'orders.commodity_snapshot',
                'orders.commodity_activity_snapshot',
                'orders.client_name',
                'orders.client_phone',
                'orders.client_address',
                'orders.total_amount',
                'orders.freight',
                'orders.status',
                'orders.management_notes',
                'orders.created_at'
            ]);
    }

    public function bindValue(Cell $cell, $value)
    {
        if (is_numeric($value)) {
            $cell->setValueExplicit($value, DataType::TYPE_STRING);

            return true;
        }

        // else return default behavior
        return parent::bindValue($cell, $value);
    }
}
